/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2007 Philippe Durand <draekz@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Collections.Generic;
using System.Reflection;

using Galaxium.Core;
using Galaxium.Protocol;

using Mono.Addins;
using Anculus.Core;

namespace Galaxium.Client
{
	public delegate void TransferEventHandler (TransferEventArgs args);
	
	public static class FileTransferUtility
	{
		public static event TransferEventHandler TransferAdded;
		public static event TransferEventHandler TransferRemoved;
		
		private static List<IFileTransfer> _transfers = new List<IFileTransfer> ();
		private static IConfigurationSection _config = Configuration.Transfer.Section;
		
		public static List<IFileTransfer> Transfers { get { return _transfers; } }
		
		public static TransferAutomationState Automation
		{
			get { return (TransferAutomationState)_config.GetInt (Configuration.Transfer.Automation.Name, Configuration.Transfer.Automation.Default); }
			set { _config.SetInt (Configuration.Transfer.Automation.Name, (int)value); }
		}
		
		public static TransferOverwriteState Overwrite
		{
			get { return (TransferOverwriteState)_config.GetInt (Configuration.Transfer.Overwrite.Name, Configuration.Transfer.Overwrite.Default); }
			set { _config.SetInt (Configuration.Transfer.Overwrite.Name, (int)value); }
		}
		
		public static TransferOverwriteAction OverwriteDefault
		{
			get { return (TransferOverwriteAction)_config.GetInt (Configuration.Transfer.OverwriteDefault.Name, Configuration.Transfer.OverwriteDefault.Default); }
			set { _config.SetInt (Configuration.Transfer.OverwriteDefault.Name, (int)value); }
		}
		
		public static string DestinationFolder
		{
			get {
				string dir = _config.GetString (Configuration.Transfer.DestinationFolder.Name, Configuration.Transfer.DestinationFolder.Default);
				
				if (string.IsNullOrEmpty(dir))
				{
					dir = GuessFolder ("Incomplete", "incomplete", "tmp", "temp");
					_config.SetString (Configuration.Transfer.DestinationFolder.Name, dir);
				}
				
				return dir;
			}
			set { _config.SetString (Configuration.Transfer.DestinationFolder.Name, value); }
		}
		
		public static string CompleteFolder
		{
			get {
				string dir = _config.GetString (Configuration.Transfer.CompleteFolder.Name, Configuration.Transfer.CompleteFolder.Default);
				
				if (string.IsNullOrEmpty(dir))
				{
					dir = GuessFolder ("Downloads", "download", "downloads", "complete");
					_config.SetString (Configuration.Transfer.CompleteFolder.Name, dir);
				}
				
				return dir;
			}
			set { _config.SetString (Configuration.Transfer.CompleteFolder.Name, value); }
		}
		
		public static bool AutoDestination
		{
			get { return _config.GetBool (Configuration.Transfer.AutoDestination.Name, Configuration.Transfer.AutoDestination.Default); }
			set { _config.SetBool (Configuration.Transfer.AutoDestination.Name, value); }
		}
		
		public static bool IsActive
		{
			get
			{
				bool isActive = false;
				
				foreach (IFileTransfer transfer in Transfers)
				{
					if (transfer.State == TransferState.Progressing)
						isActive = true;
				}
				
				return isActive;
			}
		}
		
		public static int ActiveCount
		{
			get
			{
				int count = 0;
				
				foreach (IFileTransfer transfer in Transfers)
					if (transfer.State == TransferState.Started || transfer.State == TransferState.Pending || transfer.State == TransferState.Progressing)
						count++;
				
				return count;
			}
		}
		
		public static int InactiveCount
		{
			get
			{
				int count = 0;
				
				foreach (IFileTransfer transfer in Transfers)
					if (transfer.State != TransferState.Started && transfer.State != TransferState.Pending && transfer.State != TransferState.Progressing)
						count++;
				
				return count;
			}
		}
		
		static FileTransferUtility ()
		{
			BaseUtility.CreateDirectoryIfNeeded (DestinationFolder);
			BaseUtility.CreateDirectoryIfNeeded (CompleteFolder);
		}
		
		public static void Add (IFileTransfer transfer)
		{
			ThrowUtility.ThrowIfNull ("transfer", transfer);
			
			_transfers.Add (transfer);
			
			transfer.TransferFinish += TransferFinished;
			
			if (TransferAdded != null)
				TransferAdded (new TransferEventArgs (transfer));
		}
		
		public static void Remove (IFileTransfer transfer)
		{
			ThrowUtility.ThrowIfNull ("transfer", transfer);
			
			_transfers.Remove (transfer);
			
			transfer.TransferFinish -= TransferFinished;
			
			if (TransferRemoved != null)
				TransferRemoved (new TransferEventArgs (transfer));
		}
		
		public static void ClearCompleted ()
		{
			List<IFileTransfer> list = new List<IFileTransfer>();
			
			foreach (IFileTransfer transfer in _transfers)
			{
				if (transfer.State == TransferState.Finished || transfer.State == TransferState.Cancelled ||
					transfer.State == TransferState.Aborted || transfer.State == TransferState.Declined ||
					transfer.State == TransferState.Failed)
				{
					list.Add (transfer);
				}
			}
			
			foreach (IFileTransfer transfer in list)
				Remove (transfer);
		}
		
		public static void RemoveInactive ()
		{
			IFileTransfer transfer = GetInactive();
			
			while (transfer != null)
			{
				Remove (transfer);
				transfer = GetInactive ();
			}
		}
		
		public static IFileTransfer GetInactive ()
		{
			foreach (IFileTransfer transfer in Transfers)
			{
				if (transfer.State != TransferState.Started && transfer.State != TransferState.Pending &&
				    transfer.State != TransferState.Progressing)
					return transfer;
			}
			
			return null;
		}
		
		public static bool Contains (IFileTransfer transfer)
		{
			ThrowUtility.ThrowIfNull ("transfer", transfer);
			
			return _transfers.Contains (transfer);
		}
		
		private static void TransferFinished (object sender, FileTransferEventArgs args)
		{
			if (args.FileTransfer.Incoming)
			{
				string source = Path.Combine(DestinationFolder, args.FileTransfer.FileName);
				
				if (File.Exists (source))
				{
					string destination = Path.Combine(args.FileTransfer.Destination, Path.GetFileName(args.FileTransfer.FileName));
					
					if (source.Equals(destination))
						return;
					
					if (File.Exists (destination))
						File.Delete (destination);
					
					File.Move(source, destination);
				}
				else
					Log.Warn ("Unable to find file to move it to the completed folder: "+args.FileTransfer.FileName);
			}
		}
		
		private static string GuessFolder (string defaultDir, params string[] suggestions)
		{
			string home = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
			foreach (string dir in Directory.GetDirectories (home)) {
				if (dir.StartsWith ("."))
					continue; //skip hidden dirs
				
				string dirname = Path.GetFileName (dir);
				foreach (string suggestion in suggestions) {
					if (string.Compare (dirname, suggestion, true) == 0)
						return Path.Combine (home, dirname);
				}
			}
			
			return Path.Combine (home, defaultDir);
		}
	}
}
